// Package admin
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2023 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
package admin

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"hotgo/internal/consts"
	"hotgo/internal/dao"
	"hotgo/internal/library/contexts"
	"hotgo/internal/model/entity"
	"hotgo/internal/model/input/apiin"
	"hotgo/internal/model/input/sysin"
	"hotgo/internal/service"
	"math"
)

type sProduct struct{}

func init() {
	service.RegisterProduct(NewProduct())
}

func NewProduct() *sProduct {
	return &sProduct{}
}

// IntegralBenefitsList 积分权益列表
func (s *sProduct) IntegralBenefitsList(ctx context.Context, in *apiin.IntegralBenefitsInp) (list []*apiin.IntegralBenefitsModel, totalCount int, err error) {
	location := fmt.Sprintf("%f %f", in.Lng, in.Lat)
	am := &entity.AdminMember{}
	userId := contexts.GetUserId(ctx)
	if userId != 0 {
		err = dao.AdminMember.Ctx(ctx).WherePri(userId).Scan(am)
		if err != nil {
			return nil, 0, err
		}
	}
	canBuy := ""
	if am != nil &&
		am.MemberStatus == consts.AdminMemberMemberStatusMember &&
		am.ExchangeCount != 0 &&
		am.ExpireTime != nil &&
		am.MemberStartTime != nil {
		canBuy = fmt.Sprintf(`
			,
		       	 (
					SELECT 
						CASE 
							WHEN COUNT(1) < %d THEN TRUE 
							ELSE FALSE 
						END AS is_count_less_than_three
					FROM hg_order 
					WHERE status IN ('已完成', '已付款', '待核销', '申请退款', '退款中', '已核销')
					  AND product_id = subquery.id 
					  AND user_id = %d 
					  AND use_points = 0
					  AND created_at BETWEEN '%s' AND '%s'
				) AS canBuy
		`, am.ExchangeCount, am.Id, am.MemberStartTime.Format("Y-m-d H:i:s"), am.ExpireTime.Format("Y-m-d H:i:s"))
	}
	err = dao.Product.Ctx(ctx).Raw(fmt.Sprintf(`
		SELECT * %s
			FROM (
				SELECT 
					p.id,
					p.name,
					p.main_image,
					p.integral,
					p.benefit_points,
					(SELECT COUNT(*) FROM hg_order o WHERE o.product_id = p.id AND o.status = '已完成') AS user_count,
					ROUND(ST_Distance_Sphere(s.location, ST_GeomFromText('POINT(%s)')) / 1000, 1) as distance,
					ROW_NUMBER() OVER (
						PARTITION BY p.id
						ORDER BY ST_Distance_Sphere(
							s.location, ST_GeomFromText('POINT(%s)')
						)
					) AS rn
				FROM 
					hg_product p
				LEFT JOIN 
					hg_product_store ps ON p.id = ps.product_id
				LEFT JOIN 
					hg_store s ON ps.store_id = s.id
				WHERE 
					p.type = 1
					AND p.status = 1
				ORDER BY 
					p.click DESC
			) subquery
				WHERE
					rn = 1
			`, canBuy, location, location)).Page(in.Page, in.PerPage).ScanAndCount(&list, &totalCount, false)
	if err != nil {
		return nil, 0, err
	}
	return
}

// ProductGroupBuyList 团购列表
func (s *sProduct) ProductGroupBuyList(ctx context.Context, in *apiin.ProductGroupBuyInp) (list []*apiin.ProductGroupBuyModel, totalCount int, err error) {

	if in.Lng == 0 && in.Lat == 0 {
		err = dao.Product.DB().Raw(fmt.Sprintf(`
			SELECT *
				FROM (
					SELECT 
						a.id, 
						a.name as productName, 
						a.main_image as mainImage, 
						c.name as storeName,
						a.benefit_points, 
						a.market_price,
						a.sale_price,
						(CAST(a.sale_price AS DECIMAL(10, 2)) / CAST(a.market_price AS DECIMAL(10, 2))) * 10 AS discount,
						ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY a.created_at DESC) AS rn
					FROM hg_product a
					LEFT JOIN hg_product_store b ON a.id = b.product_id
					LEFT JOIN hg_store c ON b.store_id = c.id
					WHERE 
					    a.type = 3 
					  	AND a.status = 1
						AND a.scene = 1
					ORDER BY 
					    a.click DESC,
					    a.created_at
			) subquery
			WHERE rn = 1
		`)).Page(in.Page, in.PerPage).ScanAndCount(&list, &totalCount, false)
	} else {
		location := fmt.Sprintf("%f %f", in.Lng, in.Lat)
		err = dao.Product.DB().Raw(fmt.Sprintf(`
		SELECT *
			FROM (
				SELECT 
					c.id, 
					c.name as productName, 
					c.main_image as mainImage, 
					a.name as storeName, 
					c.benefit_points as benefitPoints, 
					c.market_price, c.sale_price, 
					(CAST(c.sale_price AS DECIMAL(10, 2)) / CAST(c.market_price AS DECIMAL(10, 2))) * 10 AS discount,
					ROUND(
						ST_Distance_Sphere(
							a.location, ST_GeomFromText('POINT(%s)')
						) / 1000, 1
					) as distance, 
					ROW_NUMBER() OVER (
						PARTITION BY c.id
						ORDER BY ST_Distance_Sphere(
							a.location, ST_GeomFromText('POINT(%s)')
						)
					) AS rn
				FROM
					hg_store a
					LEFT JOIN hg_product_store b ON a.id = b.store_id
					LEFT JOIN hg_product c ON b.product_id = c.id
				WHERE
					c.id IS NOT NULL
					AND c.type = 3
					AND c.status = 1
					AND c.scene = 1
				ORDER BY 
					DENSE_RANK() OVER (
						ORDER BY FLOOR(distance)
					), 
					c.click DESC,
					distance
				) subquery
			WHERE
    			rn = 1
		`, location, location)).Page(in.Page, in.PerPage).ScanAndCount(&list, &totalCount, false)
	}
	if err != nil {
		return nil, 0, err
	}
	return
}

// ProductInfo 获取商品信息
func (s *sProduct) ProductInfo(ctx context.Context, in *apiin.ProductInfoInp) (res *apiin.ProductInfoModel, err error) {

	if in.ProductId == 0 && in.ProductNewId == 0 {
		err = gerror.New("商品ID不能为空")
		return
	}

	res = &apiin.ProductInfoModel{}

	// 查询新人商品信息
	productNew := &entity.ProductNew{}
	if in.ProductNewId != 0 {
		err = dao.ProductNew.Ctx(ctx).WherePri(in.ProductNewId).Scan(&productNew)
		if err != nil {
			return nil, err
		}
		in.ProductId = productNew.ProductId
	}

	// 查询商品信息
	err = dao.Product.Ctx(ctx).WherePri(in.ProductId).Scan(&res)
	if err != nil && err.Error() == "sql: no rows in result set" {
		err = gerror.New("商品不存在")
		return
	} else if err != nil {
		return nil, err
	}

	// 如果是新人商品，修改积分价格
	if productNew.ProductId != 0 {
		res.Integral = productNew.NewPrice
		res.ProductNewId = productNew.Id
	}

	// 查询门店信息
	md := dao.ProductStore.Ctx(ctx).
		Fields("hg_store.*")
	if in.Lat != 0 && in.Lng != 0 { // 定位信息不为空
		location := fmt.Sprintf("ROUND(ST_Distance_Sphere(hg_store.location, ST_GeomFromText('POINT(%f %f)')) / 1000, 1) as distance", in.Lng, in.Lat)
		md = md.Fields(location)
	}
	md = md.LeftJoin(dao.Store.Table(), "hg_product_store.store_id = hg_store.id").
		Where("hg_product_store.product_id = ?", in.ProductId)
	if in.Lat != 0 && in.Lng != 0 { // 定位信息不为空
		md = md.OrderAsc("distance")
	}
	err = md.Scan(&res.Stores)
	if err != nil {
		return nil, err
	}

	// 会员商品限购设置
	if consts.IsUserRole(contexts.GetRoleId(ctx)) {
		// 默认可购买
		res.CanBuy = true
		if res.Type == consts.ProductTypePoint { // 积分权益
			pass, count, limit, err := service.SysUserOrder().CheckLimit(ctx, in.ProductId, contexts.GetUserId(ctx))
			if err != nil {
				return nil, err
			}
			res.MemberQuantityLimit = limit
			res.MemberQuantity = count
			res.MemberCanBuy = pass
		}
		//else if res.Type == consts.ProductTypeGroup { // 团购商品
		// 商品限购校验
		{
			switch res.RestrictionType {
			case 1: // 根据时间周期限购
				pass, count, err := service.SysUserOrder().CycleBuyCheck(ctx, sysin.ProductViewModel{
					entity.Product{
						Id:            res.Id,
						Cycle:         res.Cycle,
						QuantityLimit: res.QuantityLimit,
					},
				})
				if err != nil {
					return nil, err
				}
				res.Quantity = count
				res.CanBuy = pass
			case 2: // 根据用户限购
				pass, count, err := service.SysUserOrder().UserBuyCheck(ctx, contexts.GetUserId(ctx), sysin.ProductViewModel{
					entity.Product{
						Id:            res.Id,
						QuantityLimit: res.QuantityLimit,
					},
				})
				if err != nil {
					return nil, err
				}
				res.Quantity = count
				res.CanBuy = pass
			}
		}
		//}
	}

	// 获取销量
	sales := &entity.Order{}
	err = dao.Order.Ctx(ctx).FieldSum("qty", "qty").
		Where(dao.Order.Columns().ProductId, in.ProductId).
		WhereIn(dao.Order.Columns().Status, consts.UserOrderStatusPayStatus).
		Scan(&sales)
	if err != nil {
		return nil, err
	}
	res.Sales = gconv.Int(sales.Qty)

	// TODO 人名币积分兑换比例 临时设置
	//res.ExchangeRatio = 0.1
	//res.BonusPoints = math.Floor(res.SalePrice / 10)
	res.ExchangeRatio = 1
	res.BonusPoints = math.Floor(res.SalePrice)
	return
}

// StoreGroupBuy 门店团购列表
func (s *sProduct) StoreGroupBuy(ctx context.Context, in *apiin.StoreGroupBuyInp) (list []*apiin.StoreGroupBuyModel, totalCount int, err error) {
	list = make([]*apiin.StoreGroupBuyModel, 0)
	err = dao.ProductStore.Ctx(ctx).FieldsPrefix(dao.Product.Table(), apiin.StoreGroupBuyModel{}).
		LeftJoin(dao.Product.Table(), "hg_product_store.product_id = hg_product.id").
		Where(dao.ProductStore.Columns().StoreId, in.ID).
		Where(dao.Product.Table()+"."+dao.Product.Columns().Status, 1). // 已上架
		Where(dao.Product.Table()+"."+dao.Product.Columns().Type, 3).   // 团购商品
		OrderDesc(dao.Product.Columns().Click).
		Page(in.Page, in.PerPage).
		ScanAndCount(&list, &totalCount, false)
	if err != nil {
		return nil, 0, err
	}
	return
}

// GetByProductId 根据ID获取商品信息
func (s *sProduct) GetByProductId(ctx context.Context, in *apiin.GetByProductIdInp) (res *apiin.GetByProductIdModel, err error) {
	res = new(apiin.GetByProductIdModel)
	err = dao.Product.Ctx(ctx).FieldsPrefix(dao.Product.Table(), apiin.GetByProductIdModel{}).
		Where(dao.Product.Columns().Id, in.ProductId).
		Scan(&res)
	return
}

// 添加点击数
func (s *sProduct) AddClick(ctx context.Context, productId int64) (err error) {
	err = dao.Product.Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		_, err = tx.Model(dao.Product.Table()).Data(g.Map{
			dao.Product.Columns().Click: gdb.Raw("click + 1"),
		}).Where(dao.Product.Columns().Id, productId).Update()
		return
	})
	return
}

// 搜索商品
func (s *sProduct) SearchProduct(ctx context.Context, in *apiin.SearchProductInp) (list []*apiin.SearchProductModel, totalCount int, err error) {
	list = make([]*apiin.SearchProductModel, 0)
	err = dao.Product.Ctx(ctx).FieldsPrefix(dao.Product.Table(), apiin.SearchProductModel{}).
		WhereLike(dao.Product.Columns().Name, "%"+in.KeyWord+"%").
		Where(dao.Product.Columns().Status, 1).
		OrderDesc(dao.Product.Columns().Click).
		Page(in.Page, in.PerPage).
		ScanAndCount(&list, &totalCount, false)
	if err != nil {
		return nil, 0, err
	}
	return
}

// 根据商品ID获取门店ID和商户ID
func (s *sProduct) GetStoreInfo(ctx context.Context, in *apiin.GetStoreInfoInp) (res *apiin.GetStoreInfoModel, err error) {
	res = new(apiin.GetStoreInfoModel)
	err = dao.ProductStore.Ctx(ctx).As("a").Fields("b.id as store_id,b.business_id").
		LeftJoin(dao.Store.Table()+" b", "a.store_id = b.id").
		Where("a."+dao.ProductStore.Columns().ProductId, in.Id).
		Scan(&res)
	if err != nil {
		return nil, err
	}
	return
}
